<?php

	class Login {

		/**
		 * Custom Error message for an invalid user e-mail.
		 * @var string
		 */
		const ERROR_USER_EMAIL_INVALID = 'User account with this e-mail id was not found!';

		/**
		 * Custom Error message for an invalid login name.
		 * @var string
		 */
		const ERROR_USER_LOGIN_INVALID = 'User account with this login name was not found!';

		/**
		 * Custom Error Message for an invalid password.
		 * @var string
		 */
		const ERROR_VALIDATE_LOGIN = "Incorrect password!";

		/**
		 * Custom Error Message when a user has 5 or more invalid logins.
		 * @var string
		 */
		const ERROR_BANNED_LOGIN = "Sorry, you have been banned from viewing this page!";

		/**
		 * If unavailable user related information is asked.
		 * @var string
		 */
		const ERROR_INVALID_QUERY = "Invalid query oserved! Possible correct values are : ";
		
		/**
		 * If information from a logged out user is accessed.
		 * @var string
		 */
		const ERROR_USER_LOGOUT = 'Unable to access info of logged out user!';

		/**
		 * If all of sudden user's browser's signature changes display security alert.
		 * @var string
		 */ 
		const WARNING_SECURITY_ISSUE = 'Unexpected user agent switch found!';

		/**
		 * 
		 * @var string
		 */
		const ERROR_UNKNOWN_CLIENT = "Unknown client!";

		/**
		 * Maximum number of invalid tries that a user can make for logging in.
		 * @var string
		 */
		const MAX_PASS_CHECKS = 15;

		/**
		 * User's login status will be 0 when that user will be log out.
		 * @var integer
		 */
		const USER_LOGGED_OUT = 0;
		
		/**
		 * User's login status will be 1 when that user will be log in.
		 * @var integer
		 */
		const USER_LOGGED_IN = 1;
		
		/**
		 * User's login status will be -1 when user supplies incorrect password.
		 * @var integer
		 */
		const INVALID_PASSWORD = -1;
		
		/**
		 * User's login status will be -2 when an un-available login name will be provided.
		 * @var integer
		 */
		const INVALID_LOGIN = -2;
		
		/**
		 * User's login status will be -3 when an un-registered e-mail will be provided.
		 * @var integer
		 */
		const INVALID_EMAIL = -3;
		
		/**
		 * User's login status will be -4 when that user is banned from being login.
		 * @var integer
		 */
		const USER_BANNED = -4;
		
		/**
		 * User's login status will be -5 when the user must re-enter his password.
		 * @var integer
		 */
		const SECURITY_CHECK = -5;

		/**
		 * Determines the user's login status.
		 * 0 = Logout, 1 = Login, -1 = Incorrect password, -2 = unavailable userLogin provided,
		 * -3 = un-registered user email provided, -4 = Banned user, -5 = Security check, 2 = not yet checked
		 * @var unknown_type
		 */ 
		public static $loginStatus = 2;

		private static $_clientId = 0;
		private static $_loginName = "";
		private static $_password = "";
		private static $_cookieExpireDuration = 8640000; //100 days by default
		private static $_cookieParams = array();

		private static $userInfo = array();
		private static $_userObj = false;

		public static function getLoggedInUser() {
			return self::$_userObj;
		}

		public static function isBanned() {
			if( isset( $_SESSION[ 'login_failed' ] ) ) {
				if( $_SESSION[ 'login_failed' ] > self::MAX_PASS_CHECKS ) {
					return true;
				}
			}
			return false;
		}

		private static function fillInfo( $user ) {
			self::$_userObj = $user;
			self::$userInfo = $user->varDump();
			$user->update( 'secondLastActiveTime||' . $user->getLastActiveTime(), 'lastActiveTime||' . date( 'Y-m-d H:i:s' ) );
		}

		public static function login( $userLoginOrEmail, $userPassword, $remember = true, $softwareLogin = false ) {
			if( self::isBanned() ) {
				return self::$loginStatus = -4;
			}
			if( !$softwareLogin ) {
				$userPassword = md5( $userPassword );
			}
			$user = false;
			try {
				if( isValidEmailId( $userLoginOrEmail ) ) {
					$users = getMultiple( 'user', "email||$userLoginOrEmail" );
					if( $users->getResultcount() < 1 ) {
						$_SESSION[ 'login_failed' ] = isset( $_SESSION[ 'login_failed' ] ) ? $_SESSION[ 'login_failed' ] : 0;
						$_SESSION[ 'login_failed' ]++;
						return self::$loginStatus = -3;
					} else {
						$user = $users->get( 0 );
					}
				}
				if( $user === false ) {
					$users = $users = getMultiple( 'user', "login||$userLoginOrEmail" );
					if( $users->getResultcount() < 1 ) {
						$_SESSION[ 'login_failed' ] = isset( $_SESSION[ 'login_failed' ] ) ? $_SESSION[ 'login_failed' ] : 0;
						$_SESSION[ 'login_failed' ]++;
						return self::$loginStatus = -2;
					} else {
						$user = $users->get( 0 );
					}
				}
			} catch( Exception $ex ) {
				throw $ex;
			}
			$userId = $user->getUserId();
			$userDbPassword = $user->getPassword();
			$userLoginOrEmail = $user->getLogin();
			$userStatus = $user->getStatus();
			if( $userDbPassword == $userPassword && ( $userStatus == 'verified' || $softwareLogin ) ) {

				// send mail while login to the system

				$objMail = new MailUtility();
				$result = $objMail->sendLoginAlertMail( $user->getName(), $user->getEmail(), $user->getLogin() );

				$_SESSION[ 'user_login' ] = $userLoginOrEmail;
				$_SESSION[ 'user_agent_hash' ] = md5( $_SERVER[ 'HTTP_USER_AGENT' ] );
				$_SESSION[ 'user_pass' ] = md5( crc32( $userPassword ) );
				$_SESSION[ 'software_login' ] = $softwareLogin ? 'yes' : 'no';
				unset( $_SESSION[ 'login_failed' ] );
				self::$loginStatus = 1;
				self::fillInfo( $user );
				if( $remember ) {
					setcookie( 'pt_auth_key', $userLoginOrEmail, time() + 604800, '/', ini_get( 'session.cookie_domain' ) );
					setcookie( 'pt_auth_token', md5( crc32( $userDbPassword ) ), time() + 604800, '/', ini_get( 'session.cookie_domain' ) );
				}
				return self::$loginStatus;
			} else {
				$_SESSION[ 'login_failed' ] = isset( $_SESSION[ 'login_failed' ] ) ? $_SESSION[ 'login_failed' ] : 0;
				$_SESSION[ 'login_failed' ]++;
				return self::$loginStatus = -1;
			}
		}

		private function __construct() {} // no need to instanciate

		public static function logout() {
			/*if( self::$loginStatus != self::USER_LOGGED_IN ) {
				return false;
			}*/
			session_destroy();
			unset( $_SESSION[ 'user_login' ] );
			unset( $_SESSION[ 'user_agent_hash' ] );
			unset( $_SESSION[ 'user_pass' ] );
			unset( $_SESSION[ 'login_failed' ] );
			
			$_SESSION = array();
			setcookie( 'pt_auth_key', '', time() - 604800, '/', ini_get( 'session.cookie_domain' ) );
			setcookie( 'pt_auth_token', '', time() - 604800, '/', ini_get( 'session.cookie_domain' ) );
		    self::$loginStatus = 0;
			setcookie( session_name(), '', time() - 604800, '/', ini_get( 'session.cookie_domain' ) );
			return true;
		}

		public static function checkLoginStatus() {
			if( self::$loginStatus != 2 ) {
				return self::$loginStatus;
			}
			if( isset( $_SESSION[ 'user_login' ] ) ) {
				$userAgentHash = md5( $_SERVER[ 'HTTP_USER_AGENT' ] );
				if( $_SESSION[ 'user_agent_hash' ] !== $userAgentHash ) {
					return self::$loginStatus = -5;
				}
				$usersObj = getMultiple( 'user', "login||" . $_SESSION[ 'user_login' ] );
				if( $usersObj->getResultCount() > 0 ) {
					$userStatus = $usersObj->getStatus();
					if( $_SESSION[ 'user_pass' ] == md5( crc32( $usersObj->getPassword() ) )  && ( $userStatus=='verified' || $_SESSION[ 'software_login' ] == 'yes' ) ) {
						self::$loginStatus = 1;
						self::fillInfo( $usersObj->get( 0 ) );
					} else {
						session_destroy();
						setcookie( 'pt_auth_key', '', time() - 604800, '/' ,ini_get('session.cookie_domain'));
						setcookie( 'pt_auth_token', '', time() - 604800, '/' ,ini_get('session.cookie_domain'));
						return self::$loginStatus = -5;
					}
				} else {
					session_destroy();
					setcookie( 'pt_auth_key', '', time() - 604800, '/' ,ini_get('session.cookie_domain'));
					setcookie( 'pt_auth_token', '', time() - 604800, '/' ,ini_get('session.cookie_domain'));
					self::$loginStatus = 0;
				}
			} else if( isset( $_COOKIE[ 'pt_auth_key' ] ) && isset( $_COOKIE[ 'pt_auth_token' ] ) ) {
				$userLogin = $_COOKIE[ 'pt_auth_key' ];
				$userPassHash = $_COOKIE[ 'pt_auth_token' ];
				$usersObj = getMultiple( 'user', "login||$userLogin" );
				if( $usersObj->getResultcount() > 0 ) {
					$user = $usersObj->get( 0 );
					$userStatus = $user->getStatus();
					
					$userDbPass = $user->getPassword();
					if( $userPassHash == md5( crc32( $userDbPass ) ) && ( $userStatus=='verified' ) ) {
						$_SESSION[ 'user_login' ] = $userLogin;
						$_SESSION[ 'user_agent_hash' ] = md5( $_SERVER[ 'HTTP_USER_AGENT' ] );
						$_SESSION[ 'user_pass' ] = $userPassHash;
						$_SESSION[ 'software_login' ] = 'no';
						unset( $_SESSION[ 'login_failed' ] );
						setcookie( 'pt_auth_key', $userLogin, time() + 604800, '/' ,ini_get('session.cookie_domain'));
						setcookie( 'pt_auth_token', md5( crc32( $userDbPass ) ), time() + 604800, '/' ,ini_get('session.cookie_domain'));
						self::$loginStatus = 1;
						self::fillInfo( $user );
					} else {
						setcookie( 'pt_auth_key', $userLogin, time() - 604800, null,ini_get('session.cookie_domain') );
						setcookie( 'pt_auth_token', 'pass', time() - 604800, null,ini_get('session.cookie_domain') );
						self::$loginStatus = 0;
					}
				} else {
					setcookie( 'pt_auth_key', $userLogin, time() - 604800, null,ini_get('session.cookie_domain') );
					setcookie( 'pt_auth_token', 'pass', time() - 604800, null,ini_get('session.cookie_domain') );
					self::$loginStatus = 0;
				}
			} else {
				self::$loginStatus = 0;
			}			
			return self::$loginStatus;
		}

		public static function getUserInfo( $about ) {
			if( self::$loginStatus != 1 ) {
				return '';
				throw new Exception( self::ERROR_USER_LOGOUT );
			}
			if( !isset( self::$userInfo[ $about ] ) ) {
				throw new Exception( self::ERROR_INVALID_QUERY . '<b>' . implode( '</b>, <b>', array_keys( self::$userInfo ) ) . '</b>.' );
			} else {
				return self::$userInfo[ $about ];
			}
		}
	}
